#ifndef __Entity_H__
#define __Entity_H__

#include "defines.h"
#include "video/SceneNode.h"
#include "video/MovableObject.h"
#include "video/Mesh.h"
#include "video/SubEntity.h"
#include "video/Skeleton.h"
#include "video/Animation.h"
#include "video/AxisAlignedBox.h"
#include "video/DummyObject.h"
#include "video/Renderable.h"
#include <string>
#include <map>

namespace KEngine
{
class Device;
class MeshManager;
class SceneManager;
class Entity : public MovableObject, public Renderable
{
public:
	union FrameList
	{
	   SkeletalAnimation*				skeletonFrames;
	   MeshAnimation*					meshFrames;

	   FrameList()	: skeletonFrames(NULL), meshFrames(NULL) {}
	};
	struct AnimationSet
	{
		Animation*	animation;
		FrameList		frames;

		AnimationSet() { animation = new Animation; }
		~AnimationSet() { KSafeDelete(animation); }
	};

	typedef std::map<std::string, DummyObject*> ChildObjectMap;
	typedef ChildObjectMap::iterator ChildObjectIterator;
	typedef ChildObjectMap::const_iterator ConstChildObjectIterator;
	typedef ChildObjectMap::value_type ChildObjectValue;

public:
	Entity(Mesh* mesh,MeshManager* meshMgr);
	virtual ~Entity();

	static Entity*	createEntity(const char* filename,MeshManager* meshMgr,SceneManager* sceneMgr);

	virtual void		setAttached(SceneNode* parent);

	virtual void		attachSkeleton(Skeleton* skeleton);
	virtual bool		hasAnimation();

	virtual float		getAlpha() const;
	virtual void		setAlpha(float alpha);

	virtual void		render(Camera* camera, TimeValue t);

	virtual void		setAnimation(const std::string& name);
	virtual void		playAnimation(TimeValue t, bool loop = true);
	virtual void		setAnimationSpeed(float speed);
	virtual void		stopAnimation();

	virtual const		AxisAlignedBox& getWorldBoundingBox(bool derive = false);
	virtual const		AxisAlignedBox& getBoundingBox();

	virtual SceneNode* getChildObject(const std::string& name);

	Mesh*				getMesh();

	virtual void		_updateRenderQueue(RenderQueue* queue, Camera* cam);
	virtual float		getSquaredViewDepth(Camera* cam) const;

protected:
	virtual void		buildSubEntityList();
	virtual void		buildChildObjects(SceneManager* mgr);
	virtual void		updateAnimation(TimeValue t);
	virtual void		_setRenderStates();
	virtual void		_resetRenderStates();

	virtual void		_notifyAttached(SceneNode* parent);
	virtual void		_notifySkeletonAttached(Skeleton* skeleton);
	virtual AxisAlignedBox getChildWorldBoundingBox();

protected:
	Mesh*				mMesh;
	AnimationSet*		mAnimation;
	
	SubEntityList		mSubEntityList;
	ChildObjectMap		mChildObjectList;

	AxisAlignedBox		mFullBoundingBox;

	float				mAlpha;

	// vertex blend mode(whether to use software processing), only used when the entity
	// has a skeleton attached
	bool				mUseSoftwareVP;

	Device*				mDevice;
	MeshManager*		mMeshMgr;
};

}
#endif //